package org.artifact.protocol;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicInteger;

import org.artifact.protocol.convert.AbstractConvert;

import cn.hutool.core.util.StrUtil;

public class ProtocolResolve {
	AbstractConvert convert;
	
	public ProtocolResolve(AbstractConvert convert) {
		super();
		this.convert = convert;
	}

	public ProtocolSend resolveSend(String classPath,String beforeLine,String line) {
		String content = StrUtil.split(line, ":")[1];
		String request = StrUtil.split(content, "->")[0];
		String requestName = StrUtil.subBefore(request, "(", true);

		Map<String, ProtocolType> requestParameter = new TreeMap<>();
		for (String parameter : StrUtil.split(StrUtil.subBetween(request, "(", ")"), ",")) {
			String[] parame = StrUtil.split(parameter, " ");
			ProtocolType type = convert.convert(classPath,parame[0]);
			String name = parame[1];
			requestParameter.put(name, type);
		}

		String response = StrUtil.split(line, "->")[1];
		Map<String, ProtocolType> responseParameter = new TreeMap<>();
		for (String parameter : StrUtil.split(StrUtil.subBetween(response, "(", ")"), ",")) {
			String[] parame = StrUtil.split(parameter, " ");
			ProtocolType type = convert.convert(classPath,parame[0]);
			String name = parame[1];
			responseParameter.put(name, type);
		}

		String remark = StrUtil.subAfter(beforeLine, "//", true).trim();

		short id = (short) (requestName.hashCode() & Short.MAX_VALUE);

		return new ProtocolSend(id, requestName, requestParameter, responseParameter, remark);
	}

	public ProtocolPush resolvePush(String classPath,String beforeLine,String line) {
		String content = StrUtil.split(line, ":")[1];
		String pushName = StrUtil.subBefore(content, "(", true);

		Map<String, ProtocolType> pushParameter = new TreeMap<>();
		for (String parameter : StrUtil.split(StrUtil.subBetween(content, "(", ")"), ",")) {
			String[] parame = StrUtil.split(parameter, " ");
			ProtocolType type = convert.convert(classPath,parame[0]);
			String name = parame[1];
			pushParameter.put(name, type);
		}

		String remark = StrUtil.subAfter(beforeLine, "//", true).trim();
		short id = (short) (pushName.hashCode() & Short.MAX_VALUE);
		return new ProtocolPush(id, pushName, pushParameter, remark);
	}

	public ProtocolStruct resolveStruct(String classPath,String beforeLine,String line, List<String> lines, AtomicInteger lineNumber) {
		String structName = "";
		String extendsName = "";
		if (line.contains("extends")) {
			structName = StrUtil.subBetween(line, ProtocolConstant.STRUCT, "extends").trim();	
			extendsName = StrUtil.subBetween(line, "extends", "{").trim();
		}else {
			structName = StrUtil.subBetween(line, ProtocolConstant.STRUCT, "{").trim();	
		}
		Map<ProtocolField, ProtocolType> fields = new LinkedHashMap<>();
		while (!"}".equals(line = lines.get(lineNumber.incrementAndGet()))) {
			if(StrUtil.isBlank(line)) {
				continue;
			}
			List<String> parameter = StrUtil.split(line, " ", 2, true, true);
			ProtocolType type = convert.convert(classPath,parameter.get(0));
			
			String name = StrUtil.subBefore(parameter.get(1), ";", false);
			String remark = StrUtil.subAfter(line, "//", true).trim();
			ProtocolField field = new ProtocolField(name, remark);
			fields.put(field, type);
		}
		
		String remark = StrUtil.subAfter(beforeLine, "//", true).trim();
		
		return new ProtocolStruct(StrUtil.upperFirst(structName),extendsName, fields, remark);
	}

	public ProtocolEnum resolveEnum(String beforeLine,String line, List<String> lines, AtomicInteger lineNumber) {
		String enumName = StrUtil.subBetween(line, ProtocolConstant.ENUM, "{").trim();
		Map<String, ProtocolField> fields = new LinkedHashMap<>();
		while (!"}".equals(line = lines.get(lineNumber.incrementAndGet()))) {
			if(StrUtil.isBlank(line)) {
				continue;
			}
			String remark = StrUtil.subAfter(line, "//", true).trim();
			line = StrUtil.subBefore(line, ",", false);
			line = StrUtil.subBefore(line, ";", false);
			String[] l = StrUtil.split(line, ":");
			
			String name = StrUtil.subBefore(l[1], ";", false);
			ProtocolField field = new ProtocolField(name, remark);
			
			
			fields.put(l[0], field);
		}
		String remark = StrUtil.subAfter(beforeLine, "//", true).trim();
		return new ProtocolEnum(StrUtil.upperFirst(enumName), fields, remark);
	}
}
